package com.ocm.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;

import com.ocm.controller.util.OCMUtil;
import com.ocm.controller.validator.SecurityValidator;
import com.ocm.core.dto.GroupDto;
import com.ocm.core.dto.UserInfoDto;
import com.ocm.core.service.SecurityService;

@Controller
@SessionAttributes("finalProfile")
public class SecurityController {

   public static final String LIST_PAGE = "group/list";
   public static final String CREATE_PAGE = "group/create";
   public static final String EDIT_PAGE = "group/edit";
   public static final String STATUS_PAGE = "group/status";

   public static final String USER_LIST_PAGE = "user/list";
   public static final String USER_CREATE_PAGE = "user/create";
   public static final String USER_EDIT_PAGE = "user/edit";
   public static final String USER_CREATE_ADDFORM_PAGE = "user/addForm";
   public static final String USER_CREATE_REVIEWFORM_PAGE = "user/reviewForm";
   public static final String USER_CREATE_GROUP_PAGE = "user/groups";
   public static final String USER_STATUS_PAGE = "user/status";
   public static final String USER_CREATE_REVIEWEDITFORM_PAGE = "user/reviewEditForm";
   public static final String USER_CREATE_EDITFORM_PAGE = "user/editForm";

   private SecurityService securityService;
   private SecurityValidator securityValidator;

   @Autowired
   public SecurityController(
      @Qualifier("securityService") SecurityService securityService,
      @Qualifier("securityValidator") SecurityValidator securityValidator) {
      this.securityService = securityService;
      this.securityValidator = securityValidator;
   }

   @RequestMapping(value = "/sec/group/list", method = RequestMethod.GET)
   public String viewListPage(Model model) {
      List<GroupDto> groupDtos = this.securityService.findGroups();
      model.addAttribute("groups", groupDtos);
      return LIST_PAGE;
   }

   @RequestMapping(value = "/sec/group/create", method = RequestMethod.GET)
   public String viewCreatePage(Model model) {
      return CREATE_PAGE;
   }

   @RequestMapping(value = "/sec/group/create", method = RequestMethod.POST)
   public String createPage(@ModelAttribute("group")GroupDto groupDto, BindingResult result, Model model) {
      this.securityValidator.validate(groupDto, result);
      if (!result.hasErrors()){
         groupDto.setIsEnabled(true);
         this.securityService.saveGroup(groupDto);
      }
      return STATUS_PAGE;
   }

   @RequestMapping(value = "/sec/group/{groupId}/edit", method = RequestMethod.GET)
   public String viewEditPage(@PathVariable("groupId")long groupId, Model model) {
      GroupDto groupDto = this.securityService.findByGroupId(groupId);
      model.addAttribute("group",groupDto);
      return EDIT_PAGE;
   }
   
   @RequestMapping(value = "/sec/group/{groupId}/edit", method = RequestMethod.POST)
   public String editGroup(@PathVariable("groupId")long groupId, @ModelAttribute("group")GroupDto groupDto, BindingResult result, ModelMap model) {
      groupDto.setId(groupId);
      GroupDto existGroup = this.securityService.findByGroupId(groupId);
      this.securityValidator.validateGroup(groupDto, existGroup, result);
      if (!result.hasErrors()){
         this.securityService.saveGroup(groupDto);
      }
      return STATUS_PAGE;
   }

   @RequestMapping(value = "/sec/user/list", method = RequestMethod.GET)
   public String viewUsers(Model model) {
      List<UserInfoDto> userDtos = this.securityService.findAllUser();
      model.addAttribute("users", userDtos);
      return USER_LIST_PAGE;
   }

   @RequestMapping(value = "/sec/user/create", method = RequestMethod.GET)
   public String viewCreateUserPage(ModelMap model, SessionStatus status) {
      if (model.containsKey("finalProfile")){
         model.remove("finalProfile");
         status.setComplete();
      }
      return USER_CREATE_PAGE;
   }

   @RequestMapping(value = "/sec/user/add", method = RequestMethod.POST)
   public String createUserPage(@ModelAttribute("user")UserInfoDto userInfoDto, BindingResult result, ModelMap model) {
      this.securityValidator.validateUser(userInfoDto, null, result);
      if (!result.hasErrors()){
         model.addAttribute("finalProfile", userInfoDto);
      }
      return USER_STATUS_PAGE;
   }

   @RequestMapping(value = "/sec/user/addForm", method = RequestMethod.GET)
   public String viewAddForm(Model model) {
      return USER_CREATE_ADDFORM_PAGE;
   }

   @RequestMapping(value = "/sec/user/group", method = RequestMethod.GET)
   public String viewGroupList(ModelMap model) {
      List<GroupDto> groupDtos = this.securityService.findGroups();
      model.addAttribute("groups", groupDtos);
      return USER_CREATE_GROUP_PAGE;
   }

   @RequestMapping(value = "/sec/user/group/assign", method = RequestMethod.POST)
   public String assignGroups(@RequestParam("JSONPropertyIds") String jsonProperties,ModelMap model) {
      Long[] ids = OCMUtil.convertIDsFromJsonString(jsonProperties);
      List<GroupDto> groupDtos = this.securityService.findGroups(ids);
      UserInfoDto userInfoDto = (UserInfoDto) model.get("finalProfile");
      userInfoDto.setUserDetails(groupDtos);
      return USER_STATUS_PAGE;
   }
   
   @RequestMapping(value = "/sec/user/review", method = RequestMethod.GET)
   public String viewReviewForm(ModelMap model) {
      UserInfoDto userInfoDto =  (UserInfoDto) model.get("finalProfile");
      userInfoDto.setIsAccountNonExpired(true);
      userInfoDto.setIsAccountNonLocked(true);
      userInfoDto.setIsCredentialsNonExpired(true);
      model.put("user", userInfoDto);
      return USER_CREATE_REVIEWFORM_PAGE;
   }
   
   @RequestMapping(value = "/sec/user/create", method = RequestMethod.POST)
   public String addUser(ModelMap model) {
      UserInfoDto userInfoDto =  (UserInfoDto) model.get("finalProfile");
      this.securityService.addUser(userInfoDto);
      return USER_STATUS_PAGE;
   }

   @RequestMapping(value = "/sec/user/{userId}/edit", method = RequestMethod.GET)
   public String viewEditUserPage(@PathVariable("userId") long userId, ModelMap model, SessionStatus status) {
      if (model.containsKey("finalProfile")){
         model.remove("finalProfile");
      }
      UserInfoDto userInfoDto = this.securityService.findByUserId(userId);
      model.put("finalProfile", userInfoDto);
      return USER_EDIT_PAGE;
   }

   @RequestMapping(value = "/sec/user/{userId}/editForm", method = RequestMethod.GET)
   public String viewEditUserFrom(@PathVariable("userId") long userId, ModelMap model, SessionStatus status) {
      return USER_CREATE_EDITFORM_PAGE;
   }

   @RequestMapping(value = "/sec/user/{userId}/editForm", method = RequestMethod.POST)
   public String viewEditUserPage(@PathVariable("userId") long userId,@ModelAttribute("user")UserInfoDto userInfoDto, BindingResult result, ModelMap model) {
      UserInfoDto finalUserInfo = (UserInfoDto) model.get("finalProfile");
      userInfoDto.setId(userId);
      this.securityValidator.validateUser(userInfoDto, finalUserInfo, result);
      if (!result.hasErrors()){
         finalUserInfo.setUsername(userInfoDto.getUsername());
         finalUserInfo.setPassword(userInfoDto.getPassword());
         finalUserInfo.setIsEnabled(userInfoDto.getIsEnabled());
      }
      return USER_STATUS_PAGE;
   }

   @RequestMapping(value = "/sec/user/{userId}/group", method = RequestMethod.GET)
   public String viewEditGroupList(ModelMap model) {
      UserInfoDto finalUserInfo = (UserInfoDto) model.get("finalProfile");
      List<GroupDto> assignedGroups = finalUserInfo.getUserDetails();
      List<GroupDto> groupDtos = this.securityService.findGroups();
      model.addAttribute("groups", OCMUtil.getRestGroups(groupDtos, assignedGroups));
      model.addAttribute("assignedGroups", assignedGroups);
      return USER_CREATE_GROUP_PAGE;
   }

   @RequestMapping(value = "/sec/user/{userId}/review", method = RequestMethod.GET)
   public String reviewEditForm(ModelMap model) {
      return USER_CREATE_REVIEWEDITFORM_PAGE;
   }

   @RequestMapping(value = "/sec/user/{userId}/edit", method = RequestMethod.POST)
   public String editUser(ModelMap model, SessionStatus status) {
      UserInfoDto userInfoDto =  (UserInfoDto) model.get("finalProfile");
      this.securityService.addUser(userInfoDto);
      model.remove("finalProfile");
      status.setComplete();
      return USER_STATUS_PAGE;
   }
}
